/*
* @desc:  反射相关工具方法
* @Author: lfzxs@qq.com
* @Date:   2022/5/10 9:28
 */
package libUtils

import (
	"encoding/json"
	"fmt"
	"reflect"
	"strconv"
)



/**
*  item:  字段项
*  value: 项值对象
**/
type ForEachStructCallBakck func (item reflect.StructField,value any)



func FieldInfoCallBack(item reflect.StructField,value any){
	field := item
	fmt.Printf("%s offset %d anonymous %t type %s exported %t json tag %s\n",
			field.Name,            //变量名称
			field.Offset,          //相对于结构体首地址的内存偏移量，string类型会占据16个字节
			field.Anonymous,       //是否为匿名成员
			field.Type,            //数据类型，reflect.Type类型
			field.IsExported(),    //包外是否可见（即是否以大写字母开头）
			field.Tag.Get("json")) //获取成员变量后面``里面定义的tag
}


// 遍历结构体成员

func ForEachStruct(model any,callback ForEachStructCallBakck){

	typeOf := reflect.TypeOf(model)  //需要用struct的Type
	valueOf := reflect.ValueOf(model)

	//如果是指针
	if typeOf.Kind() == reflect.Ptr {
		typeOf = typeOf.Elem()
		valueOf = valueOf.Elem()
	}

	fieldNum := typeOf.NumField()     //成员变量的个数
	for i := 0; i < fieldNum; i++ {
		field := typeOf.Field(i)
		value := valueOf.Field(i).Interface()
		//存在子级结构
		if field.Type.Kind() == reflect.Struct {
			ForEachStruct(value, callback)
		 }
   
		callback(field,value)	
	}
}

// 取结构体指定名称成员的值
func GetStructItemValue(model any,name string)(any,bool){
	var result any
	typeOf := reflect.TypeOf(model)  //需要用struct的Type
	valueOf := reflect.ValueOf(model)
	_,ok := typeOf.FieldByName(name)
	
	if(ok){
		result = valueOf.FieldByName(name).Interface()
	}
	

	return result,ok
}


//interface{}转换成字符串
func InterfaceToString(value interface{}) string {
	// interface 转 string
	var key string
	if value == nil {
	   return key
	}

	switch value := value.(type) {
	case float64:
	   ft := value
	   key = strconv.FormatFloat(ft, 'f', -1, 64)
	case float32:
	   ft := value
	   key = strconv.FormatFloat(float64(ft), 'f', -1, 64)
	case int:
	   it := value
	   key = strconv.Itoa(it)
	case uint:
	   it := value
	   key = strconv.Itoa(int(it))
	case int8:
	   it := value
	   key = strconv.Itoa(int(it))
	case uint8:
	   it := value
	   key = strconv.Itoa(int(it))
	case int16:
	   it := value
	   key = strconv.Itoa(int(it))
	case uint16:
	   it := value
	   key = strconv.Itoa(int(it))
	case int32:
	   it := value
	   key = strconv.Itoa(int(it))
	case uint32:
	   it := value
	   key = strconv.Itoa(int(it))
	case int64:
	   it := value
	   key = strconv.FormatInt(it, 10)
	case uint64:
	   it := value
	   key = strconv.FormatUint(it, 10)
	case string:
	   key = value
	case []byte:
	   key = string(value)
	default:
	   newValue, _ := json.Marshal(value)
	   key = string(newValue)
	}
  
	return key
 }
